package com.zndroid.utils.impl;

import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresPermission;

import com.zndroid.utils.XUtils;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 设备类型工具类
 */
@SuppressWarnings("unused")
public class DeviceUtil {
    private final static String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
    private final static String KEY_FLYME_VERSION_NAME = "ro.build.display.id";
    private final static String KEY_EMUI_VERSION_NAME = "ro.build.version.emui";
    private final static String FLYME = "flyme";
    private final static String ZTEC2016 = "zte c2016";
    private final static String ZUKZ1 = "zuk z1";
    private final static String[] MEIZUBOARD = {"m9", "M9", "mx", "MX"};
    private static String sMiuiVersionName;
    private static String sFlymeVersionName;
    private static String sEmuiVersionName;
    private static boolean sIsTabletChecked = false;
    private static boolean sIsTabletValue = false;
    private final static String BRAND = Build.BRAND.toLowerCase();

    public DeviceUtil() {
        init();
    }

    private void closeIOQuietly(final Closeable... closeables) {
        if (closeables == null) {
            return;
        }
        for (Closeable closeable : closeables) {
            if (closeable != null) {
                try {
                    closeable.close();
                } catch (IOException ignored) {
                }
            }
        }
    }

    @SuppressLint("PrivateApi")
    private void init() {
        Properties properties = new Properties();

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            // android 8.0，读取 /system/uild.prop 会报 permission denied
            FileInputStream fileInputStream = null;
            try {
                fileInputStream = new FileInputStream(new File(Environment.getRootDirectory(), "build.prop"));
                properties.load(fileInputStream);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                closeIOQuietly(fileInputStream);
            }
        }

        Class<?> clzSystemProperties;
        try {
            clzSystemProperties = Class.forName("android.os.SystemProperties");
            Method getMethod = clzSystemProperties.getDeclaredMethod("get", String.class);
            //MIUI
            sMiuiVersionName = getLowerCaseName(properties, getMethod, KEY_MIUI_VERSION_NAME);
            //FLYME
            sFlymeVersionName = getLowerCaseName(properties, getMethod, KEY_FLYME_VERSION_NAME);
            //EMUI
            sEmuiVersionName = getLowerCaseName(properties, getMethod, KEY_EMUI_VERSION_NAME);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public String getFlymeVersionName() {
        return sFlymeVersionName;
    }

    public String getEMUIVersionName() {
        return sEmuiVersionName;
    }

    public String getMIUIVersionName() {
        return sMiuiVersionName;
    }

    private boolean _isTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >=
                Configuration.SCREENLAYOUT_SIZE_LARGE;
    }

    /**
     * 判断设备是否是手机
     *
     * @return {@code true}: 是<br>{@code false}: 否
     */
    public boolean isPhone() {
        TelephonyManager tm = (TelephonyManager) XUtils.getContext().getSystemService(Context.TELEPHONY_SERVICE);
        return tm != null && tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
    }

    /**
     * 判断是否为平板设备
     */
    public boolean isTablet(Context context) {
        if (sIsTabletChecked) {
            return sIsTabletValue;
        }
        sIsTabletValue = _isTablet(context);
        sIsTabletChecked = true;
        return sIsTabletValue;
    }

    /**
     * 判断是否是flyme系统
     */
    public boolean isFlyme() {
        return !TextUtils.isEmpty(sFlymeVersionName) && sFlymeVersionName.contains(FLYME);
    }

    /**
     * 判断是否是MIUI系统
     */
    public boolean isMIUI() {
        return !TextUtils.isEmpty(sMiuiVersionName);
    }

    public boolean isMIUIV5() {
        return "v5".equals(sMiuiVersionName);
    }

    /**
     * 判断是否为emui
     * Is emui boolean.
     *
     * @return the boolean
     */
    public boolean isEMUI() {
        return !TextUtils.isEmpty(sEmuiVersionName);
    }

    /**
     * 判断是否为emui3.1版本
     * Is emui 3 1 boolean.
     *
     * @return the boolean
     */
    public boolean isEMUI3_1() {
        String property = sEmuiVersionName;
        return "EmotionUI 3".equals(property) || property.contains("EmotionUI_3.1");
    }

    /**
     * 判断是否为emui3.0版本
     * Is emui 3 1 boolean.
     *
     * @return the boolean
     */
    public boolean isEMUI3_0() {
        String property = sEmuiVersionName;
        return property.contains("EmotionUI_3.0");
    }

    /**
     * 判断是否为emui3.x版本
     * Is emui 3 x boolean.
     *
     * @return the boolean
     */
    public boolean isEMUI3_x() {
        return isEMUI3_0() || isEMUI3_1();
    }

    public boolean isMIUIV6() {
        return "v6".equals(sMiuiVersionName);
    }

    public boolean isMIUIV7() {
        return "v7".equals(sMiuiVersionName);
    }

    public boolean isMIUIV8() {
        return "v8".equals(sMiuiVersionName);
    }

    public boolean isMIUIV9() {
        return "v9".equals(sMiuiVersionName);
    }

    public boolean isFlymeVersionHigher5_2_4() {
        //查不到默认高于5.2.4
        boolean isHigher = true;
        if (sFlymeVersionName != null && !"".equals(sFlymeVersionName)) {
            String regex = "(\\d+\\.){2}\\d";
            Pattern p = Pattern.compile(regex);
            Matcher matcher = p.matcher(sFlymeVersionName);
            if (matcher.find()) {
                String versionString = matcher.group();
                if (!"".equals(versionString)) {
                    String[] version = versionString.split("\\.");
                    if (version.length == 3) {
                        if (Integer.parseInt(version[0]) < 5) {
                            isHigher = false;
                        } else if (Integer.parseInt(version[0]) > 5) {
                            isHigher = true;
                        } else {
                            if (Integer.parseInt(version[1]) < 2) {
                                isHigher = false;
                            } else if (Integer.parseInt(version[1]) > 2) {
                                isHigher = true;
                            } else {
                                if (Integer.parseInt(version[2]) < 4) {
                                    isHigher = false;
                                } else if (Integer.parseInt(version[2]) >= 5) {
                                    isHigher = true;
                                }
                            }
                        }
                    }

                }
            }
        }
        return isMeizu() && isHigher;
    }

    public boolean isMeizu() {
        return isMeiZuBoard() || isFlyme();
    }

    /**
     * 判断是否为小米
     * https://dev.mi.com/doc/?p=254
     */
    public boolean isXiaomi() {
        return "xiaomi".equalsIgnoreCase(Build.MANUFACTURER);
    }

    public boolean isVivo() {
        return BRAND.contains("vivo") || BRAND.contains("bbk");
    }

    public boolean isOppo() {
        return BRAND.contains("oppo");
    }

    public boolean isHuawei() {
        return BRAND.contains("huawei") || BRAND.contains("honor");
    }

    public boolean isEssentialPhone() {
        return BRAND.contains("essential");
    }

    /**
     * 判断是否为 ZUK Z1 和 ZTK C2016。
     * 两台设备的系统虽然为 android 6.0，但不支持状态栏icon颜色改变，因此经常需要对它们进行额外判断。
     */
    public boolean isZUKZ1() {
        final String board = Build.MODEL;
        return board != null && board.toLowerCase().contains(ZUKZ1);
    }

    public boolean isZTKC2016() {
        final String board = Build.MODEL;
        return board != null && board.toLowerCase().contains(ZTEC2016);
    }

    /*魅族主板*/
    private boolean isMeiZuBoard() {
        final String board = Build.BOARD;
        if (board == null) {
            return false;
        }
        for (String board1 : DeviceUtil.MEIZUBOARD) {
            if (board.equals(board1)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断悬浮窗权限（目前主要用于魅族与小米的检测）。
     */
    public boolean isFloatWindowOpAllowed(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            // 24 是AppOpsManager.OP_SYSTEM_ALERT_WINDOW 的值，该值无法直接访问
            return checkOp(context, 24);
        } else {
            try {
                return (context.getApplicationInfo().flags & 1 << 27) == 1 << 27;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    }

    @TargetApi(19)
    private boolean checkOp(Context context, int op) {
        final int version = Build.VERSION.SDK_INT;
        if (version >= Build.VERSION_CODES.KITKAT) {
            AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            try {
                @SuppressLint("DiscouragedPrivateApi")
                Method method = manager.getClass().getDeclaredMethod("checkOp", int.class, int.class, String.class);
                int property = (Integer) method.invoke(manager, op,
                        Binder.getCallingUid(), context.getPackageName());
                return AppOpsManager.MODE_ALLOWED == property;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    @Nullable
    private String getLowerCaseName(Properties p, Method get, String key) {
        String name = p.getProperty(key);
        if (name == null) {
            try {
                name = (String) get.invoke(null, key);
            } catch (Exception ignored) {
            }
        }
        if (name != null) {
            name = name.toLowerCase();
        }
        return name;
    }


    /**
     * 获取当前手机系统语言。
     *
     * @return 返回当前系统语言。例如：当前设置的是“中文-中国”，则返回“zh-CN”
     */
    public String getSystemLanguage() {
        return Locale.getDefault().getLanguage();
    }

    /**
     * 获取当前手机系统版本号(like: android 9 10 11)
     *
     * @return 系统版本号
     */
    public String getSystemVersion() {
        return android.os.Build.VERSION.RELEASE;
    }

    /**
     * 获取当前手机系统API版本号(like: API 28 29 30)
     *
     * @return 系统API版本号
     */
    public int getSystemVersionInt() {
        return android.os.Build.VERSION.SDK_INT;
    }

    /**
     * 获取手机型号
     *
     * @return 手机型号
     */
    public String getSystemModel() {
        return android.os.Build.MODEL;
    }

    /**
     * 获取手机厂商
     *
     * @return 手机厂商
     */
    public String getDeviceBrand() {
        if (TextUtils.isEmpty(android.os.Build.BRAND)) {
            return getDeviceManufacturer();
        }
        return android.os.Build.BRAND;
    }

    /**
     * 获取手机制造商
     *
     * @return The manufacturer of the product/hardware
     */
    public String getDeviceManufacturer() {
        return Build.MANUFACTURER;
    }

    /**
     * An ordered list of ABIs supported by this device
     *
     * @return ABI
     */
    public String[] getABIs() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return Build.SUPPORTED_ABIS;
        } else {
            return new String[]{Build.CPU_ABI, Build.CPU_ABI2};
        }
    }

    /**
     * A build ID string meant for displaying to the user(like:TAS-AL00 2.0.0.209(C00E208R6P6))
     *
     * @return build id
     * */
    public String getBuildId() {
        return Build.DISPLAY;
    }

    /**
     * The name of the hardware (from the kernel command line or /proc).
     *
     * @return hardware like (kirin990)
     * */
    public String getHardWare() {
        return Build.HARDWARE;
    }

    /**
     * The name of the industrial design.
     *
     * @return name like (HWTAS)
     * */
    public String getDeviceName() {
        return Build.DEVICE;
    }

    /**
     * The name of the user settings.(有时候会不准，依赖蓝牙)
     *
     * @return name like (HUAWEI Mate30)
     * */
    public String getDeviceNameByUser(Context context) {
        return Settings.Secure.getString(context.getContentResolver(), "bluetooth_name");
    }

    public String getDeviceHost() {
        return Build.HOST;
    }

    /**
     * 获取华为鸿蒙系统版本名称
     * @return String  返回值：harmony
     * */
    @SuppressLint("PrivateApi")
    public String getHarmonyOsName() {
        try {
            Class<?> clz = Class.forName("com.huawei.system.BuildEx");
            return (String) clz.getMethod("getOsBrand").invoke(clz);
        } catch (Throwable e) {
            //ignore
        }
        return "";
    }

    /**
     * 获取华为鸿蒙系统版本号
     * @return 版本号
     */
    public String getHarmonyOsVersion() {
        return getProp("hw_sc.build.platform.version", "");
    }

    @SuppressLint("PrivateApi")
    public String getProp(String property, String defaultValue) {
        try {
            Class<?> spClz = Class.forName("android.os.SystemProperties");
            Method method = spClz.getDeclaredMethod("get", String.class);
            String value = (String) method.invoke(spClz, property);
            if (TextUtils.isEmpty(value)) {
                return defaultValue;
            }
            return value;
        } catch (Throwable e) {
            //ignore
        }
        return defaultValue;
    }

    @SuppressLint({"MissingPermission", "HardwareIds"})
    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
    public String getSerialNumber(Context context) {
        String deviceId;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
        } else {
            final TelephonyManager mTelephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (context.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                    return "";
                }
            }
            assert mTelephony != null;
            if (mTelephony.getDeviceId() != null) {//@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    deviceId = mTelephony.getImei();//@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
                } else {
                    deviceId = mTelephony.getDeviceId();
                }
            } else {
                deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
            }
        }
        return deviceId;
    }

    /**
     * 获取移动终端类型
     *
     * @return 手机制式
     * <ul>
     * <li>{@link TelephonyManager#PHONE_TYPE_NONE } : 0 手机制式未知</li>
     * <li>{@link TelephonyManager#PHONE_TYPE_GSM  } : 1 手机制式为 GSM，移动和联通</li>
     * <li>{@link TelephonyManager#PHONE_TYPE_CDMA } : 2 手机制式为 CDMA，电信</li>
     * <li>{@link TelephonyManager#PHONE_TYPE_SIP  } : 3</li>
     * </ul>
     */
    public int getPhoneType() {
        TelephonyManager tm = (TelephonyManager) XUtils.getContext().getSystemService(Context.TELEPHONY_SERVICE);
        return tm != null ? tm.getPhoneType() : -1;
    }

    /**
     * 判断 sim 卡是否准备好
     *
     * @return {@code true}: 是<br>{@code false}: 否
     */
    public boolean isSimCardReady() {
        TelephonyManager tm = (TelephonyManager) XUtils.getContext().getSystemService(Context.TELEPHONY_SERVICE);
        return tm != null && tm.getSimState() == TelephonyManager.SIM_STATE_READY;
    }

    /**
     * 获取 Sim 卡运营商名称
     * <p>中国移动、如中国联通、中国电信</p>
     *
     * @return sim 卡运营商名称
     */
    public String getSimOperatorName() {
        TelephonyManager tm = (TelephonyManager) XUtils.getContext().getSystemService(Context.TELEPHONY_SERVICE);
        return tm != null ? tm.getSimOperatorName() : null;
    }

    /**
     * 获取 Sim 卡运营商名称
     * <p>中国移动、如中国联通、中国电信</p>
     *
     * @return 移动网络运营商名称
     */
    public String getSimOperatorByMnc() {
        TelephonyManager tm = (TelephonyManager) XUtils.getContext().getSystemService(Context.TELEPHONY_SERVICE);
        String operator = tm != null ? tm.getSimOperator() : null;
        if (operator == null) {
            return null;
        }
        switch (operator) {
            case "46000":
            case "46002":
            case "46007":
                return "中国移动";
            case "46001":
            case "46006":
                return "中国联通";
            case "46003":
            case "46005":
            case "46011":
                return "中国电信";
            default:
                return operator;
        }
    }
}

